﻿Imports MordecaiHunter.CommonCodeLibrary.Controls.BusyIcon

Namespace Controls
    Public Class clsBusyIcon
        Inherits System.Windows.Forms.Control

        Friend Const DOT_COUNT As Integer = 8
        Friend Const UPDATE_INTERVAL As Integer = 2

        Private m_bEnabled As Boolean
        Private m_bClockwise As Boolean

        Private m_iDotRadius As Single
        Private m_iRadius As Single
        Private m_iCenterX As Single
        Private m_iCenterY As Single

        Private m_pIconType As EnumBusyIconType
        Private m_iIndex As Integer = 0
        Private m_iUpdateCounter As Integer = 0

        Private m_pDotBuffer As List(Of BusyIcon.clsDot)

        Private WithEvents m_pTimer As New Windows.Forms.Timer


        Public Sub New()
            MyBase.New()

            Me.Enabled = True
            Me.Interval = 100
            Me.Clockwise = True

            m_pDotBuffer = New List(Of BusyIcon.clsDot)
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            ' Do this each time
            RenderIcon(e.Graphics)
            UpdateIcon()

            m_iUpdateCounter += 1
            m_iUpdateCounter = m_iUpdateCounter Mod UPDATE_INTERVAL

            'MyBase.OnPaint(e)
        End Sub

        Private Sub RenderIcon(ByRef g As Drawing.Graphics)
            ' Draw every dot and discard the old
            For i = m_pDotBuffer.Count - 1 To 0 Step -1
                If m_pDotBuffer(i).Lifetime >= (DOT_COUNT - 1) Then
                    m_pDotBuffer.RemoveAt(i)
                Else
                    m_pDotBuffer(i).Draw(g)
                End If
            Next

            ' Disable after last Dot has disappeared
            If Not Me.Enabled Then
                If m_pDotBuffer.Count = 0 Then
                    m_pTimer.Enabled = False
                End If
            End If
        End Sub
        Private Sub UpdateIcon()
            ' Add new dots
            If Me.Enabled Then
                Select Case m_pIconType
                    Case EnumBusyIconType.Circle
                        ' Create new Dot
                        Dim x As Single = m_iCenterX + ((Math.Cos(m_iIndex * ((Math.PI * 2) / DOT_COUNT)) * m_iRadius) - m_iDotRadius)
                        Dim y As Single = m_iCenterY + ((Math.Sin(m_iIndex * ((Math.PI * 2) / DOT_COUNT)) * m_iRadius) - m_iDotRadius)
                        m_pDotBuffer.Add(New BusyIcon.clsDot(Me.ForeColor, New Drawing.PointF(x, y), m_iDotRadius))

                    Case EnumBusyIconType.Rectangle
                        Dim x As Single = Math.Cos(m_iIndex * ((Math.PI * 2) / DOT_COUNT))
                        Dim y As Single = Math.Sin(m_iIndex * ((Math.PI * 2) / DOT_COUNT))
                        'If Math.Abs(x) > Math.Abs(y) Then
                        '    x = m_iCenterX + Math.Round(x, 0) * m_iRadius - m_iDotRadius
                        '    y = m_iCenterY + y * m_iRadius - m_iDotRadius
                        'ElseIf Math.Abs(x) < Math.Abs(y) Then
                        '    x = m_iCenterX + x * m_iRadius - m_iDotRadius
                        '    y = m_iCenterY + Math.Round(y, 0) * m_iRadius - m_iDotRadius
                        'Else
                        '    x = m_iCenterX + Math.Round(x, 0) * m_iRadius - m_iDotRadius
                        '    y = m_iCenterY + Math.Round(y, 0) * m_iRadius - m_iDotRadius
                        'End If
                        If Math.Abs(x) > Math.Abs(y) Then
                            x = m_iCenterX + Math.Round(x, 0) * (m_iCenterX - m_iDotRadius) - m_iDotRadius
                            y = m_iCenterY + y * (m_iCenterY - m_iDotRadius) - m_iDotRadius
                        ElseIf Math.Abs(x) < Math.Abs(y) Then
                            x = m_iCenterX + x * (m_iCenterX - m_iDotRadius) - m_iDotRadius
                            y = m_iCenterY + Math.Round(y, 0) * (m_iCenterY - m_iDotRadius) - m_iDotRadius
                        Else
                            x = m_iCenterX + Math.Round(x, 0) * (m_iCenterX - m_iDotRadius) - m_iDotRadius
                            y = m_iCenterY + Math.Round(y, 0) * (m_iCenterY - m_iDotRadius) - m_iDotRadius
                        End If
                        'Dim x As Single = m_iCenterX + ((Math.Round(Math.Cos(m_iIndex * ((Math.PI * 2) / DOT_COUNT)), 0) * m_iRadius) - m_iDotRadius)
                        'Dim y As Single = m_iCenterY + ((Math.Round(Math.Sin(m_iIndex * ((Math.PI * 2) / DOT_COUNT)), 0) * m_iRadius) - m_iDotRadius)
                        m_pDotBuffer.Add(New BusyIcon.clsDot(Me.ForeColor, New Drawing.PointF(x, y), m_iDotRadius))

                    Case EnumBusyIconType.Alternate
                        Dim x As Single = m_iCenterX
                        Dim y As Single = m_iCenterY - m_iDotRadius
                        If m_iIndex <= DOT_COUNT / 2 Then
                            ' Advance to the right
                            x = (((Me.Width) / (DOT_COUNT)) + m_iDotRadius) * m_iIndex
                        Else
                            ' Advance to the left
                            x = (((Me.Width) / (DOT_COUNT)) + m_iDotRadius) * (DOT_COUNT - m_iIndex)
                        End If
                        m_pDotBuffer.Add(New BusyIcon.clsDot(Me.ForeColor, New Drawing.PointF(x, y), m_iDotRadius))

                    Case EnumBusyIconType.Marquee
                        Dim x As Single = m_iIndex * (Me.Width / DOT_COUNT)
                        Dim y As Single = m_iCenterY - m_iDotRadius
                        m_pDotBuffer.Add(New BusyIcon.clsDot(Me.ForeColor, New Drawing.PointF(x, y), m_iDotRadius))

                End Select
            End If


            For i = 0 To m_pDotBuffer.Count - 1
                m_pDotBuffer(i).Age()
            Next

            ' Step
            If m_bClockwise Then
                m_iIndex += 1
            Else
                m_iIndex -= 1
            End If

            If m_iIndex >= DOT_COUNT Then
                m_iIndex = 0
            ElseIf m_iIndex < 0 Then
                m_iIndex = DOT_COUNT - 1
            End If
            'm_iIndex = m_iIndex Mod DOT_COUNT
        End Sub

        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            m_iDotRadius = Math.Min(Me.Width, Me.Height) / (DOT_COUNT * 1.5)
            m_iRadius = Math.Min(Me.Width, Me.Height) / 2 - m_iDotRadius

            m_iCenterX = Me.Width / 2
            m_iCenterY = Me.Height / 2

            MyBase.OnResize(e)
        End Sub

        Public Property Interval As Integer
            Get
                Return m_pTimer.Interval
            End Get
            Set(ByVal value As Integer)
                If value > 0 Then
                    m_pTimer.Interval = value
                End If
            End Set
        End Property
        Public Overloads Property Enabled As Boolean
            Get
                Return m_bEnabled
            End Get
            Set(ByVal value As Boolean)
                m_bEnabled = value
                If value = True Then
                    m_pTimer.Enabled = value
                End If
            End Set
        End Property

        Public Property IconType As EnumBusyIconType
            Get
                Return m_pIconType
            End Get
            Set(ByVal value As EnumBusyIconType)
                m_pIconType = value
            End Set
        End Property
        Public Property Clockwise As Boolean
            Get
                Return m_bClockwise
            End Get
            Set(ByVal value As Boolean)
                m_bClockwise = value
            End Set
        End Property

        Private Sub m_pTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_pTimer.Tick
            Me.Refresh()
        End Sub
    End Class
End Namespace